package com.db.yupao.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.db.yupao.common.ErrorCode;
import com.db.yupao.exception.BusinessException;
import com.db.yupao.model.pojo.User;
import com.db.yupao.service.UserService;
import com.db.yupao.mapper.UserMapper;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.DigestUtils;

import java.util.HashSet;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

import static com.db.yupao.constant.UserConstant.ADMIN_ROLE;
import static com.db.yupao.constant.UserConstant.USER_LOGIN_STATE;

/**
 * @author ZhiMser(用户)】的数据库操作Service实现
 * @createDate 2024-ing
 *  * @description 针对表【u10-22 11:58:38
 */
@Service
@Slf4j
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
    @Resource
    private UserMapper userMapper;

    private static final String u = "JiMao";


    /**
     * 用户注册
     *
     * @param userAccount
     * @param userPassword
     * @param checkPassword
     * @param planetCode
     * @return
     */
    @Override
    public long userRegister(String userAccount, String userPassword, String checkPassword, String planetCode) {
        // 校验
        if (StringUtils.isAllBlank(userAccount, userPassword, checkPassword, planetCode)) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "参数为空");
        }
        if (userAccount.length() < 4) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "用户账户过短");
        }
        if (userPassword.length() < 8 || checkPassword.length() < 8) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, " 用户密码过短");
        }
        if (planetCode.length() > 5) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "星球编号过长");
        }

        // 账户不能包含特殊字符
        String validPattern = "^[a-zA-Z0-9_]+$";
        boolean isMatch = Pattern.compile(validPattern).matcher(userAccount).matches();
        if (!isMatch) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "账号包含特殊字符");
        }

        // 密码和校验密码相同
        if (!userPassword.equals(checkPassword)) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "密码和校验密码不一致");
        }

        // 账户不能重复
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("userAccount", userAccount);
        long count = this.count(queryWrapper);
        if (count > 0) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "账号重复");
        }

        // 星球编号不能重复
        queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("planetCode", planetCode);
        count = this.count(queryWrapper);
        if (count > 0) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "星球编号重复");
        }

        // 加密
        String encryptPassword = DigestUtils.md5DigestAsHex((u + userPassword).getBytes());

        // 插入数据
        User user = new User();
        user.setUserAccount(userAccount);
        user.setUserPassword(encryptPassword);
        user.setPlanetCode(planetCode);
        boolean saveResult = this.save(user);
        if (!saveResult) {
            throw new BusinessException(ErrorCode.SYSTEM_ERROR, "插入数据失败");
        }

        return user.getId();
    }

    /**
     * 用户登录
     *
     * @param userAccount
     * @param userPassword
     * @param request
     * @return
     */
    @Override
    public User userLogin(String userAccount, String userPassword, HttpServletRequest request) {
        // 校验
        if (StringUtils.isAllBlank(userAccount, userPassword)) {
            throw new BusinessException(ErrorCode.NULL_ERROR, "账号密码为空");
        }
        if (userAccount.length() < 4) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "账号过短");
        }
        if (userPassword.length() < 8) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "密码过短");
        }

        // 账户不能包含特殊字符
        String validPattern = "^[a-zA-Z0-9_]+$";
        boolean isMatch = Pattern.compile(validPattern).matcher(userAccount).matches();
        if (!isMatch) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "账号包含特殊字符");
        }

        // 查询用户是否存在
        String encryptPassword = DigestUtils.md5DigestAsHex((u + userPassword).getBytes());
        log.info("user login in, encryptPassword: " + encryptPassword);
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("userAccount", userAccount);
        queryWrapper.eq("userPassword", encryptPassword);
        User user = userMapper.selectOne(queryWrapper);
        // 用户不存在
        if (user == null) {
            log.info("user login failed, userAccount cannot match userPassword");
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "用户不存在");
        }

        User safetyUser = getSafetyUser(user);
        // 记录用户的登录态
        request.getSession().setAttribute(USER_LOGIN_STATE, safetyUser);

        return safetyUser;
    }

    /**
     * 用户脱敏
     *
     * @param originUser
     * @return
     */
    @Override
    public User getSafetyUser(User originUser) {
        if (originUser == null) {
            return null;
        }
        User safetyUser = new User();
        safetyUser.setId(originUser.getId());
        safetyUser.setUsername(originUser.getUsername());
        safetyUser.setUserAccount(originUser.getUserAccount());
        safetyUser.setAvatarUrl(originUser.getAvatarUrl());
        safetyUser.setGender(originUser.getGender());
        safetyUser.setPhone(originUser.getPhone());
        safetyUser.setEmail(originUser.getEmail());
        safetyUser.setUserStatus(originUser.getUserStatus());
        safetyUser.setCreateTime(originUser.getCreateTime());
        safetyUser.setUserRole(originUser.getUserRole());
        safetyUser.setPlanetCode(originUser.getPlanetCode());
        return safetyUser;
    }

    /**
     * 用户注销
     *
     * @param request
     * @return
     */
    @Override
    public int userLogout(HttpServletRequest request) {
        // 移除登录态
        request.getSession().removeAttribute(USER_LOGIN_STATE);
        return 1;
    }

    public static void main(String[] args) {
        Gson gson = new Gson();
        String tag = "[java,V++,gothon]";
        String tgs = "[js, 数据分析, 人工智能, 男, golang, 大一, 985]";

        Set<String> tagSet = gson.fromJson(tgs, new TypeToken<Set<String>>() {
        }.getType());
        log.info("tags:{}",tagSet.contains("女"));
//        log.info(tagSet.toString());
    }
    /**
     * 根据标签搜索用户
     * @param tagNameList
     * @return
     */
    @Override
    public List<User> searchUserByTags(List<String> tagNameList) {
        if (CollectionUtils.isEmpty(tagNameList)) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        List<User> users = userMapper.selectList(queryWrapper);
        Gson gson = new Gson();
        return users.stream().filter((user) -> {
            String tag = user.getTag();
            // 空值校验
            if (!StringUtils.isNotBlank(tag)) {
                return false;
            }
            //将json字符串转成list 对象
            Set<String> tagSet = gson.fromJson(tag, new TypeToken<Set<String>>(){}.getType());
            // 任何一个集合或数组都需要进行判空操作 Optional 为Java 1.8 的特性 避免空指针异常
            // 可以少写一层if 减少代码圈复杂度
            tagSet = Optional.ofNullable(tagSet).orElse(new HashSet<>());
            log.info("tagNameList: " + tagNameList);
            for (String tagName : tagNameList) {
                if (!tagSet.contains(tagName)) {
                    log.info("tagSet: " + tagSet);
                    log.info("tagName: " + tagName);
                    return false;
                }
            }
            return true;
        }).map(this::getSafetyUser).collect(Collectors.toList());
    }

    @Override
    public Integer updateUser(User user, User loginUser) {
        long id = user.getId();
        User userObj = userMapper.selectById(id);

        // todo 补充校验 如果用户 除了id 没有更新其他值就不予理会
        log.info("update user: " + user);
        log.info("update userObj: " + userObj);
        // 如果是管理员 ，允许更新任意用户
        if (isAdmin(loginUser) ) {
            if (id <= 0 ){
                throw new BusinessException(ErrorCode.PARAMS_ERROR);
            }
            if (userObj == null){
                throw new BusinessException(ErrorCode.NULL_ERROR);
            }
           return userMapper.updateById(user);
        }

        // 如果不是管理员用户 就只能更新自己的
        if (id == loginUser.getId()){
            log.info("21321321321321321");
            return userMapper.updateById(user);
        }
        else{
            throw new BusinessException(ErrorCode.NO_AUTH);
        }



    }

    @Override
    public User getLoginUser(HttpServletRequest request) {
        if (request == null){
            return null;
        }

        Object userOBJ = request.getSession().getAttribute(USER_LOGIN_STATE);

        if (userOBJ == null) {
            throw new BusinessException(ErrorCode.NO_AUTH);
        }

        return (User) userOBJ;
    }



    /**
     * 是否为管理员
     * @param loginUser
     * @return
     */

    @Override
    public boolean isAdmin(User loginUser) {
        // 仅管理员可删除
        return loginUser != null && loginUser.getUserRole() == ADMIN_ROLE;
    }

    /**
     * 是否为管理员
     * @param request
     * @return
     */

    @Override
    public boolean isAdmin(HttpServletRequest request) {
        // 仅管理员可删除
        Object userObj = request.getSession().getAttribute(USER_LOGIN_STATE);
        User user = (User) userObj;
        return user != null && user.getUserRole() == ADMIN_ROLE;
    }

    /**
    * 根据标签搜索用户
    *
    * @param tagNameList 用户要拥有的标签
    * @return
     */
    @Deprecated //  方法过时暂时不用  将类型转换为private 防止外部调用
    private List<User> searchUserByTagsBySQL(List<String> tagNameList) {
        if (CollectionUtils.isEmpty(tagNameList)) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        // 拼接and查询
//        for (String tagName : tagNameList) {
//            queryWrapper = queryWrapper.like("tag", tagName);
//        }
        // 将查询条件放入Mapper查询
//        List<User> users = userMapper.selectList(queryWrapper);
        //        return users.stream().map(this::getSafetyUser).collect(Collectors.toList());
        // 变例每个对象进行脱敏？

        List<User> users = userMapper.selectList(queryWrapper);
        Gson gson = new Gson();
        return users.stream().filter((user) -> {
            String tag = user.getTag();
            // 空值校验
            if (StringUtils.isNotBlank(tag)) {
                return false;
            }
            //将json字符串转成list 对象
            Set<String> tagSet = gson.fromJson(tag, new TypeToken<Set<String>>() {
            }.getType());
            for (String tagName : tagNameList) {
                if (!tagSet.contains(tagName)) {
                    return false;
                }
            }
            return true;
        }).map(this::getSafetyUser).collect(Collectors.toList());
    }
}
// 反序列化
//            gson.toJson(tagList);